package Registry;

import connection.zkConnection;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.registry.LocateRegistry;
import java.util.List;

/**
 * @author: Lixy
 * @email: 1908598362@qq.com
 * @date: 2022/2/21 星期一 11:42
 */
//注册中心，通过zk链接 和传入的Remote接口实现对象，完成RMI地址的拼接 和保存
public class RpcRegistry {
    private zkConnection connection;

    private String ip;
    private int port;

    /*
     * 1.拼接RMI的访问地址URI
     * 2.URI存储至zk中
     *
     * @throws  抛异常 表示注册失败
     * */
    public void registerService(Class<? extends Remote> serviceInterface, Remote serviceObj) throws IOException, KeeperException, InterruptedException {
        //拼接
        String Rmi = "rmi://"+ip+":"+port+"/"+serviceInterface.getName();
        //zk节点名称
        String Path = "/rpc/"+serviceInterface.getName();
        List<String> children = connection.getConn().getChildren("/rpc", false);
        if (children.contains(serviceInterface.getName())){
            Stat stat =new Stat();
            connection.getConn().getData(Path,false,stat);
            connection.getConn().delete(Path,stat.getCversion());
        }
        connection.getConn().create(Path,Rmi.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        //在Rmi的Registry上注册服务对象
        Naming.rebind(Rmi,serviceObj);
        //rmi注册服务 返回当前节点的registry的代理对象 但是相比于create方法 get有可能返回空 但是create会频繁new ，所以加上判断
        LocateRegistry.getRegistry(port);

    }

    /*
    * 根据服务类型访问zk，获取rmi服务的代理对象
    * 1.拼接zk的节点名称
    * 2.访问zk查询该节点中存储的数据
    * 3.根据查询的结果创建一个代理对象
    * */
    public <T extends Remote> T getServiceProxy(Class<T> serviceInterface) throws IOException, KeeperException, InterruptedException, NotBoundException {
        //拼接
        String Path = "/rpc/"+serviceInterface.getName();
        //查询节点
        byte[] data = connection.getConn().getData(Path, false, null);
        //查询到的字节数组转换成Sring类型的rmi地址
        String rmi = new String(data);
        //创建代理对象
        Object obj = Naming.lookup(rmi);

        return (T)obj;
    }

    public zkConnection getConnection() {
        return connection;
    }

    public void setConnection(zkConnection connection) {
        this.connection = connection;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }
}